home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DDJMAG
/
DDJ8806.ZIP
/
RTUNIX.ZIP
/
RTUNIX.LST
Wrap
File List
|
1980-01-01
|
23KB
|
800 lines
/* Listing One -- Main routine for Solution A */
#include <stdio.h> /* standard Unix I/O header */
#include <termio.h> /* file/port control headers */
#include <fcntl.h>
#include <sys/types.h> /* required headers for IPC */
#include <sys/ipc.h>
#include <sys/msg.h>
/* local constants */
#define TRUE (1==1) /* boolean values */
#define FALSE (1==0)
#define SENSOR_1_DEV "/dev/tty45"/* tty port names for sensor ports */
#define SENSOR_2_DEV "/dev/tty46"
#define SENSOR_3_DEV "/dev/tty47"
#define TIMEOUT (10L) /* timeout if no input received */
#define MAX_SENSOR_MSG (100) /* maximum size of a sensor message */
#define MAX_CMD_MSG (100) /* maximum size of a command message */
/* local function declarations */
void
process_timeout(); /* process sensor read timeout */
/* module-wide data */
int
timeout_id[3]; /* marktime timeout timer IDs */
/* Main routine for program */
main ()
{
int
cmd_size, /* number of bytes in command message */
msg_size, /* number of bytes in sensor message */
qid, /* message queue identifier */
sensor_1_fd, /* file descriptors for the sensors */
sensor_2_fd,
sensor_3_fd;
char
cmd_msg[MAX_CMD_MSG], /* buffer for reading command queue */
sensor_msg[MAX_SENSOR_MSG]; /* buffer for reading sensor data */
/* open the sensor input files */
sensor_1_fd=open(SENSOR_1_DEV,O_RDWR|O_NDELAY);
sensor_2_fd=open(SENSOR_2_DEV,O_RDWR|O_NDELAY);
sensor_3_fd=open(SENSOR_3_DEV,O_RDWR|O_NDELAY);
/* open the command queue */
qid=msgget(1,IPC_CREAT|0666);
/* establish initial timeouts for each sensor */
timeout_id[0]=marktime(TIMEOUT,(int*)NULL,process_timeout,(char*)1);
timeout_id[1]=marktime(TIMEOUT,(int*)NULL,process_timeout,(char*)2);
timeout_id[2]=marktime(TIMEOUT,(int*)NULL,process_timeout,(char*)3);
/* loop forever */
while (TRUE)
{
/* Read (or try) each sensor and process the input. */
if ( (msg_size=read(sensor_1_fd, sensor_msg, MAX_SENSOR_MSG)) > 0)
process_sensor (sensor_msg, msg_size, 1);
if ( (msg_size=read(sensor_2_fd, sensor_msg, MAX_SENSOR_MSG)) > 0)
process_sensor (sensor_msg, msg_size, 2);
if ( (msg_size=read(sensor_3_fd, sensor_msg, MAX_SENSOR_MSG)) > 0)
process_sensor (sensor_msg, msg_size, 3);
/* check for input on the message queue */
if ( (cmd_size=msgrcv(qid,cmd_msg,MAX_CMD_MSG,0,IPC_NOWAIT)) >= 0)
process_cmd_msg (cmd_msg, cmd_size);
/* delay the program before continuing loop */
nap (3);
}
}
/* Function process_cmd_msg ()
**
** This is a stub routine for handling command queue input. It suspends
** timeouts while processing the input and then resumes them when it is
** done.
*/
static process_cmd_msg (msg, size)
char
*msg; /* INPUT: pointer to command message */
int size; /* INPUT: size of *msg */
{
timer_disable();
/* (do some appropriate processing on the command) */
timer_enable();
return;
}
/* Function process_sensor()
**
** This is a stub routine for handling sensor input. It cancels the
** outstanding timeout timer and reschedule a new timeout. It also
** suspends timeout interrupts while it is processing the input.
*/
static process_sensor (msg, size, sensor_num)
char
*msg; /* INPUT: pointer to sensor data */
int
size, /* INPUT: size of *msg */
sensor_num; /* INPUT: sensor number */
{
timer_disable();
cancel_marktime (timeout_id[sensor_num-1]);
/* (do some appropriate processing on the message) */
timeout_id[sensor_num]=marktime(TIMEOUT,(int*)NULL,
process_timeout,(char*)sensor_num);
timer_enable();
return;
}
/* Function process_timeout()
**
** This is a stub for the sensor input timeout timer. It is called as a
** completion routine from marktime(), which passes the sensor number
** as an argument. The function suspends timeouts while it processing
** the error and resumes processing when it is done. It also resets the
** timeout before exiting, something that a real program may or may not
** want to do in real life, depending on the appication.
*/
static void process_timeout (sensor_num)
char
*sensor_num; /* INPUT: sensor number which has */
/* timed out (declared char* because */
/* that's what marktime() calls */
/* it with. Value is really int */
{
timer_disable();
/* (do some appropriate processing on the error) */
timeout_id[(int)sensor_num]=marktime(TIMEOUT,(int*)NULL,
process_timeout, sensor_num);
timer_enable();
return;
}
/* Listing Two -- nap() */
#include <stdio.h> /* standard Unix I/O header */
#include <termio.h> /* port file control headers */
#include <fcntl.h>
#define TRUE (1==1) /* boolean constants */
#define FALSE (1==0)
/* Function nap()
**
** This function provides a program delay function with resolution
** to a tenth of a second. It works by opening a file to /dev/clk
** (which should be linked to some unused /dev/tty), setting the
** input parameters to non-canonical, and setting the VTIME value
** to the passed argument. It then does a read on the file which
** will time out after the indicated delay time.
*/
void nap (delay)
int
delay; /* INPUT: delay in tenths of a second */
{
static int
clock_opened=FALSE; /* has the clock device been opened? */
static int
fd; /* clock file descriptor */
int
flags; /* file control flags */
char
buff[10]; /* dummy read buffer */
struct termio
clock_termio; /* terminal I/O parameters */
/*
** the first time through the routine, open the clock port
** and set the port parameters.
*/
if (!clock_opened)
{
fd=open("/dev/clk",O_RDONLY|O_NDELAY);
ioctl (fd, TCGETA, &clock_termio);
clock_termio.c_cflag |= CLOCAL;
clock_termio.c_lflag &= ~ICANON;
ioctl (fd, TCSETA, &clock_termio);
flags = fcntl (fd, F_GETFL, 0) & ~O_NDELAY;
fcntl (fd, F_SETFL, flags); clock_opened = TRUE;
}
/* set the VTIME delay to the indicated value */
ioctl (fd, TCGETA, &clock_termio);
clock_termio.c_cc[VMIN] = 0;
clock_termio.c_cc[VTIME] = delay;
ioctl (fd, TCSETAF, &clock_termio);
/* perform the dummy read */
read (fd, buff, 10);
return;
}
/* Listing Three -- marktime() and related functions */
#include <stdio.h> /* standard input/output include */
#include <sys/signal.h> /* signal definitions */
#define MAX_ELEMENT 10 /* maximum number of queued events */
#define TRUE (1==1)
#define FALSE (1==0)
struct tmq /* timer queue element structure */
{
unsigned long time; /* expiration time (UNIX) of element */
void (*ast)(); /* user ast to call at expiration */
char *arg; /* value passed to ast() (if called) */
struct tmq *next; /* pointer to next element */
int *flag; /* event count to bump at expiration */
};
static struct tmq
*queue_free, /* first available element in queue */
*queue_head, /* first element in clock queue */
*queue_tail, /* last element in clock queue */
timer_queue[MAX_ELEMENT]; /* table of queue elements */
static int
q_busy = FALSE, /* queue update in progress */
q_enabled = FALSE, /* queue countdown operations enabled */
queue_init = FALSE; /* queue initialized flag */
static unsigned long
next_event; /* last known value of expiration */
/* time of head element (may */
/* change during ast) */
extern unsigned long
time(); /* get Unix time */
extern unsigned int
alarm(); /* set system alarm clock */
void
queue_ast(); /* internal asynchronous trap */
/* Function marktime()
**
** This function inserts an element into the timer queue (performing
** queue initialization if necessary). If the new element is at the
** top of the queue, it will reset the alarm clock.
**
** Return values:
** -1 queue full
** >=0 element ID
*/
int marktime (time_of_event, flag, user_ast, user_arg)
unsigned long
time_of_event; /* INPUT: seconds until event */
char
*user_arg; /* INPUT: user-supplied argument (in */
/* reality, this could be a */
/* pointer to any data type, but */
/* char* is a good enough */
/* description */
void
(*user_ast)(); /* INPUT: user function to call at */
/* expiration (may be NULL) */
int
*flag; /* INPUT: pointer to flag to make */
/* TRUE on expiration (may be NULL)*/
{
int
element, /* offset into timer_queue */
found_slot, /* loop termination flag */
ret_val; /* >=0 element ID, -1 queue full */
register struct tmq
*new_element, /* pointer to newly added element */
*last_ptr, /* previous pointer into timer_queue */
*q_ptr; /* pointer into timer_queue */
/* if the queue is uninitialized, then initialize it */
if (!queue_init)
{
queue_free = &timer_queue[0];
for (element=0; element<MAX_ELEMENT; element++)
timer_queue[element].next = &timer_queue[element+1];
timer_queue[MAX_ELEMENT-1].next = NULL;
queue_head = NULL;
queue_tail = NULL;
q_busy = FALSE;
q_enabled = TRUE;
signal (SIGALRM, queue_ast);
queue_init = TRUE;
}
/* insert the new element into the linked list */
if ( (new_element=queue_free) != NULL)
{
q_busy = TRUE;
queue_free = queue_free->next;
new_element->time = time_of_event + time((long*)0);
if (flag != NULL)
{ new_element->flag = flag;
*flag = FALSE;
}
new_element->ast = user_ast;
new_element->arg = user_arg;
q_ptr = queue_head;
last_ptr = queue_head;
found_slot = FALSE;
while ( (q_ptr!=NULL) && !found_slot)
{
if (new_element->time < q_ptr->time)
found_slot = TRUE;
else
{
last_ptr = q_ptr;
q_ptr = q_ptr->next;
}
}
/* if the new element is first, then reset alarm for this element */
if (q_ptr == queue_head)
{
new_element->next = queue_head;
queue_head = new_element;
next_event = new_element->time;
if (q_enabled)
alarm ((unsigned int)(new_element->time - time((long*)0)));
}
else
{
new_element->next = q_ptr;
last_ptr->next = new_element;
}
ret_val = new_element - timer_queue;
q_busy = FALSE;
}
else
ret_val = (-1);
return (ret_val);
}
/* Function queue_ast()
**
** This function is called when the clock reaches the time
** at the head of the timer queue. It sets the indicated
** flag (if non-NULL), and removes the head element
** from the queue. It reschedules the internal timeout to the
** time of the new queue head element, if one exists. (If the
** time of the next element is less than the present time, the
** function schedule the event in one second.) Finally,
** if the user-supplied ast is non-NULL, it calls that routine,
** passing the user-supplied argument.
**
** The function checks the q_busy flag (set by marktime() and** cancel_marktime()) to verify that the program isn't in the
** middle of a queue update. If the flag is TRUE, queued_ast()
** reschedules itself 1 second from now, rather than attempting
** to hack at the queue blindly.
**
*/
static void queue_ast ()
{
register struct tmq
*q_ptr; /* temporary queue pointer */
unsigned int
nexttime; /* seconds until next timeout */
/*
** If it is safe to fiddle with the queue, pull out the next
** element and schedule the next timeout, if any.
*/
if (!q_busy)
{
q_ptr = queue_head;
queue_head = q_ptr->next;
q_ptr->next = queue_free;
queue_free = q_ptr;
if (queue_head != NULL)
{
if (q_enabled)
{
if ( (nexttime=(unsigned int)queue_head->time -
time((long*)0)) > 0)
alarm (nexttime);
else
alarm (1);
}
}
/* set the user's flag, if any is specified */
if (q_ptr->flag != NULL)
*q_ptr->flag = TRUE;
/* call the user's completion routine, if any specified */
if (q_ptr->ast != NULL)
(*q_ptr->ast)(q_ptr->arg);
}
/* if the queue is busy, reschedule the timeout for later */
else
{
if (q_enabled)
alarm (1);
}
/* reset signal catcher */
signal (SIGALRM, queue_ast);
return;
}
/* Function cancel_marktime()
**
** This function removes the specified timer request from the
** timer queue.
**
** Return values:
** >=0 time remaining till expiration
** <0xFFFFFFFF no such element
**
** If the queue hasn't been initialized, the function returns
** 'no such element'. It does NOT initialize the queue.
**
** The element ID, used for identifying the event to be canceled
** is returned by marktime.
*/
unsigned long cancel_marktime (id)
int
id; /* INPUT: element id (returned from */
/* marktime) */
{
register struct tmq
*last_ptr, /* previous pointer into timer_queue */
*q_ptr; /* pointer into timer_queue */
int
found; /* loop termination flag */
unsigned long
ret_val; /* >=0 for success, <0 for failure */
unsigned int
neyvtime; /* time until next event expiration */
/* make sure that the queue is initialized */
if (queue_init)
{
q_busy = TRUE;
/* make sure that the ID is legitimate */
if ( (id >= 0) && (id < MAX_ELEMENT) )
{
/*
** Traverse the event queue until we find the requested element.
** This ensures that the element has really been used and also
** gives us the pointers for relinking the list. */
for (q_ptr=queue_head, last_ptr=q_ptr, found=FALSE;
q_ptr!=NULL && !found;
last_ptr=q_ptr, q_ptr=q_ptr->next)
/* do we have a match? */
if (q_ptr == &timer_queue[id])
{
ret_val = q_ptr->time - time((long*)0);
/*
** if the cancelled element was at the head, then
** reschedule the next timeout, if any exist.
*/
if (q_ptr==queue_head)
{
queue_head = q_ptr->next;
if (queue_head != NULL)
{
if (q_enabled)
{
if ((nexttime=(unsigned int)queue_head->time
- time((long*)0)) > 0)
alarm (nexttime);
else
alarm (1);
}
}
else
alarm (0);
}
else
last_ptr->next = q_ptr->next;
q_ptr->next = queue_free;
queue_free = q_ptr;
found = TRUE;
}
/* did we ever find a match? */
if (!found)
ret_val = (-1);
}
else
ret_val = (-1);
q_busy = FALSE;
}%]se
ret_val = (-1);
return (ret_val);
}
/* Function timer_enable()
**
** This function enables normal timer queue operations. If
** there is an element on the top of the timer queue, it sets
** up the appropriate alarm; otherwise, just marks the queue
** as enabled. If the time of the next event has already passed,
** it will schedule it to happen in one second (prevents unexpected** interrupt).
*/
void timer_enable()
{
unsigned int
nexttime; /* seconds till next timeout */
q_enabled = TRUE;
if (queue_head != NULL)
{
if ( (nexttime=(unsigned int)queue_head->time - time((long*)0)) > 0)
alarm (nexttime);
else
alarm (1);
}
else
alarm (0);
return;
}
/* Function timer_disable()
**
** This function disables normal timer queue operations. If
** there is an element on the top of the timer queue, it cancels
** the alarm() timer; otherwise, just marks the queue as disabled.
*/
void timer_disable()
{
q_enabled = FALSE;
if (queue_head != NULL)
ai19m (0);
return;
}
/*Listing Four -- Sensor message definition */
/* sensor message command queue message structure */
struct message_rec
{
long mtype; /* message type */
int func; /* message function code */
int sensor_num; /* sensor number */
char data[100]; /* message data */
};
/* sensor command queue function codes */
#define SENSOR_INPUT (1)
#define SENSOR_TIMEOUT (2)
#define SENSOR_COMMAND (3)
/* Listing Five -- Main routine for Solution B */
#include <stdio.h> /* standard Unix I/O header */
#include <termio.h> /* file/port control headers */
#include <fcntl.h>
#include <sys/types.h> /* required headers for IPC */
#include <sys/ipc.h>
#include <sys/msg.h>
#include "sensor.h" /* defines sensor messages */
/* local constants */
#define TRUE (1==1) /* boolean values */
#define FALSE (1==0)
/* Main routine for program */
main ()
{
int
cmd_size, /* number of bytes in command message */
qid; /* message queue identifier */
struct message_rec
cmd_msg; /* buffer for reading queue message */
/* open the command queue */
qid=msgget(1,IPC_CREAT|0666);
/* loop forever */
while (TRUE)
{
/* wait for a new message on the command queue */
/* check for input on the message queue */
cmd_size = msgrcv (qid, &cmd_msg, sizeof(cmd_msg), 0, 0);
switch (cmd_msg.func)
{
case SENSOR_INPUT :
process_sensor (cmd_msg.data, cmd_size, cmd_msg.sensor_num);
break;
case SENSOR_TIMEOUT :
process_timeout (cmd_msg.sensor_num);
break;
case SENSOR_COMMAND :
process_cmd_msg (&cmd_msg, cmd_size);
break;
break; }
}
}
/* Function process_cmd_msg ()
**
** This is a stub routine for handling command queue input.
*/
static process_cmd_msg (msg, size)
char
*msg; /* INPUT: pointer to command message */
int
size; /* INPUT: size of *msg */
{
/* (do some appropriate processing on the command) */
}
/* Function process_sensor
**
** This is a stub routine for handling sensor input.
*/
static process_sensor (msg, size, sensor_num)
char
*msg; /* INPUT: pointer to sensor data */
int
size, /* INPUT: size of *msg */
sensor_num; /* INPUT: sensor number */
{
/* (do some appropriate processing on the message) */
}
/* Function process_timeout()
**
** This is a stub for the sensor input timeout timer.
*/
static process_timeout (sensor_num)
int
sensor_num; /* INPUT: sensor which has timed out */
{
/* (do some appropriate processing on the error) */
}
/* Listing Six -- Sensor input process (one per sensor) */
#include <stdio.h> /* standard Unix I/O header */
#include <termio.h> /* file/port control headers */
#include <fcntl.h>
#include <sys/types.h> /* required headers for IPC */
#include <sys/ipc.h>
#include <sys/msg.h>
#include "sensor.h" /* sensor command message structure */
#define TRUE (1==1) /* boolean true and false */
#define FALSE (1==0)
#define TIMEOUT (10L) /* sensor timeout delay */
main(argc,argv)
int
argc; /* INPUT: number of command line arguments */
char
*argv[]; /* INPUT: pointers to command line arguments */
{
int
flags, /* file control flags */
marktime_id, /* timeout timer ID */
qid, /* IPC message queue ID */
sensor_fd, /* file descriptor for sensor port */
timeout; /* marktime timeout flag */
char
filename[20]; /* name of port file */
struct message_rec
sensor_msg; /* buffer for sensor message */
struct termio
clock_termio; /* terminal I/O parameters */
/* open the sensor port */
sprintf (filename, "/dev/tty%d", atoi(argv[1]));
sensor_fd=open(filename,O_RDWR);
/* open IPC queue */
qid=msgget(1,IPC_CREAT|0666);
sensor_msg.mtype = 1;
sensor_msg.sensor_num = atoi(argv[1]);
/* main loop */
while (TRUE)
{
/* set up timeout */
marktime_id=marktime(TIMEOUT,&timeout,(void*)NULL,(char*)NULL);
/* read until data received or timeout timer expires */
read (sensor_fd, sensor_msg.data, sizeof(sensor_msg.data));
if (!timeout)
{
/* got data -- cancel timeout and pass to main program */
cancel_marktime (marktime_id);
sensor_msg.func = SENSOR_INPUT;
msgsnd (qid, &sensor_msg, sizeof(sensor_msg), 0);
}
else
{
/* timeout -- inform main program */
sensor_msg.func = SENSOR_TIMEOUT;
msgsnd (qid, &sensor_msg, sizeof(sensor_msg), 0);
marktime_id=marktime(TIMEOUT,&timeout,(void*)NULL,(char*)NULL);
}
}
}